package start.spring.basic.filter;

import java.io.UnsupportedEncodingException;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import start.spring.basic.util.common.StringUtil;

/**
 * 
 * ****************************************************************************
 * request日志记录
 *
 * @author(作者)：xuyongyun
 * @date(创建日期)：2023年2月2日
 ******************************************************************************
 */
@Slf4j
@Component
public class HttpRequestFilter extends BaseFilter implements GlobalFilter, Ordered {

	@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		
		//优先获取请求头中的traceId
		String requestTraceId = null;
        HttpHeaders headers = exchange.getRequest().getHeaders();
        if(headers.containsKey(super.REQUEST_KEY_TRACEID)) {
        	requestTraceId = headers.getFirst(super.REQUEST_KEY_TRACEID);
    	}
        
        //请求头未设置traceId
        if(StringUtil.isEmpty(requestTraceId)) {
        	requestTraceId = StringUtil.getUuid();
        }
        
        //前置处理
        String traceId = requestTraceId;
        
        ServerHttpRequest request = exchange.getRequest().mutate()
				.header(super.REQUEST_KEY_TRACEID, traceId)
				.build();

		String uri = request.getURI().getPath();
		String method = request.getMethodValue();
		
		log.info("[{}]:request url：{}", traceId, request.getURI().toString());
		log.info("[{}]:request method：{}", traceId, method);
		        
        for(String header:super.REQUEST_HEADER) {
        	if(headers.containsKey(header)) {
        		log.info("[{}]:request header: {} = {}", traceId, header, headers.get(header));
        	}
        }
        
        log.info("[{}]:request prams：{}", traceId, request.getQueryParams().toString());
        
        //记录post请求参数
        if(super.REQUEST_POST.equals(method)) {
        	boolean isRequestBodyRecode = true;
        	for(String denyKeyRequest:super.REQUEST_KEY_NODETAIL) {
        		if(uri.toLowerCase().indexOf(denyKeyRequest)>=0) {
        			isRequestBodyRecode = false;
        			break;
            	}
        	}
        	if(isRequestBodyRecode) {
        		
        		DefaultDataBufferFactory defaultDataBufferFactory = new DefaultDataBufferFactory();
        		DefaultDataBuffer defaultDataBuffer = defaultDataBufferFactory.allocateBuffer(0);
        		
        		return DataBufferUtils
        				.join(exchange.getRequest().getBody().defaultIfEmpty(defaultDataBuffer))
                        .flatMap(dataBuffer -> {
                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(bytes);
                            try {
                                String bodyString = new String(bytes, "utf-8");
                                log.info("[{}]:request body: {}", traceId, bodyString);
                                exchange.getAttributes().put("POST_BODY",bodyString);
                            } catch (UnsupportedEncodingException e) {
                                log.error("记录请求体出错!", e);
                            }
                            DataBufferUtils.release(dataBuffer);
                            Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                                DataBuffer buffer = exchange.getResponse().bufferFactory()
                                        .wrap(bytes);
                                return Mono.just(buffer);
                            });

                            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                    exchange.getRequest()) {
                                @Override
                                public Flux<DataBuffer> getBody() {
                                    return cachedFlux;
                                }
                            };
                            return chain.filter(exchange.mutate().request(mutatedRequest)
                                            .build());
                        });
        	}
        }
        
		return chain.filter(exchange);
    }
    
    //顺序,数值越小,优先级越高
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
    
}
